package com.pybox.service;

import com.pybox.common.utils.JdbcTemplateUtils;
import com.pybox.common.utils.ParamUtils;
import com.pybox.dto.IOTaskDto;
import com.pybox.entity.TChangNameDan;
import com.pybox.entity.TModels;
import com.pybox.repository.TChangNameDanRepository;
import com.pybox.repository.TModelsRepository;
import com.pybox.repository.TUserGroupObjectsRepository;
import com.pybox.util.CommonUtils;
import com.pybox.util.UserUtils;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * @author LeiYang
 * @title: TChangNameDanService
 * @projectName pybox
 * @description: 申请单service接口
 * @date 2019/7/3016:34
 */
@Service
@Transactional
public class TChangNameDanService {

    @Autowired
    private TChangNameDanRepository tChangNameDanRepository;

    @Autowired
    private TModelsRepository tModelsRepository;

    @Autowired
    private JdbcTemplateUtils jdbcTemplateUtils;

    //    @Autowired
//    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    //    @Autowired
//    private FormService formService;
    @Autowired
    private HistoryService historyService;

    /*保存申请单*/
    public void save(TChangNameDan dto) {

        if (dto.getObject_id() > 0) {
            //先把数据保存到申请单
            dto.setUserId(UserUtils.getCurrentUser().getId());
            dto.setUsername(UserUtils.getCurrentUser().getRealname());
            dto.setT_status(1);
            dto.setType(0); //表示是改名申请单
            dto.setCtime(new Date());
            //根据model_id查询车型
            String model = tModelsRepository.findOne(dto.getModel_id()).getModelName();
            dto.setObjectname(model + dto.getVincode6()); //新的名称
            //物品位置
            TChangNameDan dto_1 = tChangNameDanRepository.save(dto);

            //改名申请单流程开始
            if (dto_1.getId() > 0 && dto_1.getType() == 0) {

                startWorkflew(dto_1);
            }
        }
    }


    /*分页查询申请单*/
    public Page<TChangNameDan> page(Integer pageNo, Integer pageSize, Map<String, String> params) {
        Pageable pageable = new PageRequest(pageNo - 1, pageSize);
        List<Object> object = new ArrayList<>();
        StringBuffer sql = new StringBuffer(" SELECT\n" +
                "\tt.id,\n" +
                "\tt.username,\n" +
                "\tt.vincode6,\n" +
                "\tt.ctime,\n" +
                "\tt.utime,\n" +
                "\tt.reason_id,\n" +
                "\tt.t_status,\n" +
                "\tt.results,\n" +
                "\tt.type,\n" +
                "\tt.position,\n" +
                "\tt.objectname,\n" +
                "\tt.beforname,\n" +
                "\tt.token_pwd,\n" +
                "\tm.model AS objname,\n" +
                "\to.userid_autherized, \n" +
                "\to.apply \n" +
                "FROM\n" +
                "\tt_change_name_dan t\n" +
                "\tLEFT JOIN t_models m ON ( t.model_id = m.id )\n" +
                "\tLEFT JOIN t_objects o ON(t.id = o.apply)  WHERE 1 = 1");
        StringBuffer sb = new ParamUtils().getTChangNameDanParams(params, sql);

        Page<TChangNameDan> datas = jdbcTemplateUtils.page(sb, object, TChangNameDan.class, pageNo, pageSize);
        Page<TChangNameDan> page = new PageImpl<>(datas.getContent(), pageable, datas.getTotalElements());
        return page;
    }

    /*根据Id查询申请单*/
    public TChangNameDan detail(Integer id) {
        return tChangNameDanRepository.findOne(id);
    }

    /*根据Id删除了申请单*/
    public boolean delete(Integer id) {
        tChangNameDanRepository.delete(id);
        return true;
    }

    /*修改申请单*/
    public boolean update(Integer id, TChangNameDan dto) {
        List<Object> object = new ArrayList<>();

        //根据车型model_id查询 查询车型名称
        String model = jdbcTemplateUtils.query("select model from t_models where Id = ?", dto.getModel_id());
        dto.setObjectname(model + dto.getVincode6());
        StringBuffer sql = new StringBuffer("UPDATE t_change_name_dan SET ");
        StringBuffer sb = new ParamUtils().getTChangNameDanParams(id, dto, sql);
        jdbcTemplateUtils.update(sb, object);
        return true;
    }

    /**
     * 更新申请单状态，启动流程实例，让启动的流程实例关联业务
     */
    public boolean startWorkflew(TChangNameDan tChangNameDan) {
        //1：获取申请单ID，使用申请单ID，查询申请单的对象

        // TChangNameDan tChangNameDan = tChangNameDanRepository.findOne(id);
        //2：更新申请单的请假状态从0变成1（初始录入-->审核中）
        // tChangNameDan.setT_status(1);
        //3：使用当前对象获取到流程定义的key（对象的名称就是流程定义的key）
        String key = tChangNameDan.getClass().getSimpleName();
        /**
         * 4 使用流程变量设置下一个任务的办理人
         * inputUser是流程变量的名称，
         * 获取的办理人是流程变量的值
         */
        Map<String, Object> variables = new HashMap<>();
        variables.put("userID", tChangNameDan.getExamineId());//表示惟一用户
        /**
         * 5：	(1)使用流程变量设置字符串（格式：tChangNameDan.id的形式），通过设置，让启动的流程（流程实例）关联业务
         (2)使用正在执行对象表中的一个字段BUSINESS_KEY（Activiti提供的一个字段），让启动的流程（流程实例）关联业务
         */
        //格式：tChangNameDan.id的形式（使用流程变量）
        String objId = key + "." + tChangNameDan.getId();
        variables.put("objId", objId);
        //6：使用流程定义的key，启动流程实例，同时设置流程变量，同时向正在执行的执行对象表中的字段BUSINESS_KEY添加业务数据，同时让流程关联业务
        runtimeService.startProcessInstanceByKey(key, objId, variables);
        return true;
    }

    /**
     * 2：使用当前用户名查询正在执行的任务表，获取当前任务的集合List<Task>
     */
    public Page<IOTaskDto> page(Integer pageNo, Integer pageSize) {

        Pageable pageable = new PageRequest(pageNo - 1, pageSize);
        // 目标类
        List<Task> list = taskService.createTaskQuery()
                .taskAssignee(UserUtils.getUserId().toString())//指定个人任务查询
                .orderByTaskCreateTime().desc()//
                .list();

        List<IOTaskDto> lists = new ArrayList<>();

        // 循环(定义IOTask是为了解决activit 读取Task时和springboot结合时的懒加载异常)
        for (Task task : list) {
            IOTaskDto ioTask = new IOTaskDto();
            ioTask.setId(task.getId());  //任务Id
            ioTask.setAssignee(UserUtils.getCurrentUser().getRealname());  //任务办理人
            ioTask.setName(task.getName()); //任务名称
            ioTask.setCreatetime(task.getCreateTime()); //任务创建时间
            lists.add(ioTask);
        }
        //对返回的List数据做分页处理
        List list2 = CommonUtils.page(pageSize, pageNo, lists);

        Page<IOTaskDto> page = new PageImpl<>(list2, pageable, list.size());
        return page;
    }

    /**
     * 一：使用任务ID，查找请假单ID，从而获取申请单信息
     */
    public TChangNameDan detailChangNameDan(Integer taskId) {

        //1：使用任务ID，查询任务对象Task
        Task task = taskService.createTaskQuery()//
                .taskId(String.valueOf(taskId))//使用任务ID查询
                .singleResult();
        //2：使用任务对象Task获取流程实例ID
        String processInstanceId = task.getProcessInstanceId();
        //3：使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
        ProcessInstance pi = runtimeService.createProcessInstanceQuery()//
                .processInstanceId(processInstanceId)//使用流程实例ID查询
                .singleResult();
        //4：使用流程实例对象获取BUSINESS_KEY
        String buniness_key = pi.getBusinessKey();
        //5：获取BUSINESS_KEY对应的主键ID，使用主键ID，查询改名单对象（TChangNameDan.1）
        String id = "";
        if (!StringUtils.isEmpty(buniness_key)) {
            //截取字符串，取buniness_key小数点的第2个值
            id = buniness_key.split("\\.")[1];
            TChangNameDan tChangNameDan = tChangNameDanRepository.findOne(Integer.parseInt(id));
            tChangNameDan.setTaskId(taskId);
            //根据model_id查询车型
            int model_id = tChangNameDan.getModel_id();
            if (!StringUtils.isEmpty(model_id)) {
                if (tChangNameDan.getModel_id() == 0) {
                    tChangNameDan.setObjname("新");

                } else {
                    TModels tModels = tModelsRepository.findOne(tChangNameDan.getModel_id());
                    tChangNameDan.setObjname(tModels.getModelName());

                }
            }
            return tChangNameDan;
        }
        //查询改名申请单对象
        return null;
    }

    /**
     * 根据taskId处理这条信息
     */
    public Boolean dealTask(Integer id, TChangNameDan dto) {

        /*获取任务ID*/
        String tasId = dto.getTaskId().toString();
        //获取连线的名称
        String outcome = "默认提交";
        //批注信息
        String message = "";
        if (dto.getType() == 0) {
            message = "同意改名";
        } else {
            message = "授权取件码";
        }
        //获取改名申请单ID
        /**
         * 1：在完成之前，添加一个批注信息，向act_hi_comment表中添加数据，用于记录对当前申请人的一些审核信息
         */
        //使用任务ID，查询任务对象，获取流程流程实例ID
        Task task = taskService.createTaskQuery()//
                .taskId(tasId)//使用任务ID查询
                .singleResult();
        //获取流程实例ID
        String processInstanceId = task.getProcessInstanceId();
        /**
         * 注意：添加批注的时候，由于Activiti底层代码是使用：
         * 		String userId = Authentication.getAuthenticatedUserId();
         CommentEntity comment = new CommentEntity();
         comment.setUserId(userId);
         所有需要从Session中获取当前登录人，作为该任务的办理人（审核人），对应act_hi_comment表中的User_ID的字段，不过不添加审核人，该字段为null
         所以要求，添加配置执行使用Authentication.setAuthenticatedUserId();添加当前任务的审核人
         * */
        Authentication.setAuthenticatedUserId(UserUtils.getUserId().toString());//(保存的用户的Id)
        taskService.addComment(tasId, processInstanceId, message);
        /**
         * 2：如果连线的名称是“默认提交”，那么就不需要设置，如果不是，就需要设置流程变量
         * 在完成任务之前，设置流程变量，按照连线的名称，去完成任务
         流程变量的名称：outcome
         流程变量的值：连线的名称
         */
        Map<String, Object> variables = new HashMap<String, Object>();
        if (outcome != null && !outcome.equals("默认提交")) {
            variables.put("outcome", outcome);
        }

        //3：使用任务ID，完成当前人的个人任务，同时设置流程变量
        taskService.complete(tasId, variables);
        //4：当任务完成之后，需要指定下一个任务的办理人（使用类）-----已经开发完成

        /**
         * 5：在完成任务之后，判断流程是否结束
         如果流程结束了，更新改名申请单表的状态从1变成2（审核中-->审核完成）
         */
        ProcessInstance pi = runtimeService.createProcessInstanceQuery()//
                .processInstanceId(processInstanceId)//使用流程实例ID查询
                .singleResult();
        //流程结束了
        if (pi == null) {
            //更新申请单的状态从1变成2（审核中-->审核完成）

            if (dto.getType() == 0) { //同意改名
                List<Object> object = new ArrayList<>();
                tChangNameDanRepository.updateTStatus(id, message, null, new Date());
                //更新tobject中的属性
                StringBuffer sql = new StringBuffer("UPDATE t_objects SET ");
                StringBuffer sb = new ParamUtils().getTObjectParams(dto, sql);
                jdbcTemplateUtils.update(sb, object);
            }
            if (dto.getType() == 1) { //给予授权码
                List<Object> object = new ArrayList<>();
                //查询授权码
                StringBuffer sb = new StringBuffer("select token_pwd from t_objects where 1=1 ").
                        append(" and  id = '" + dto.getObject_id() + "'");

                TChangNameDan tChangNameDan = (TChangNameDan) jdbcTemplateUtils.queryForObject(sb, object, new BeanPropertyRowMapper<>(TChangNameDan.class));
                //更新申请单
                tChangNameDanRepository.updateTStatus(id, message, tChangNameDan.getToken_pwd(), new Date());
                //更新t_objects表中userid_autherized的状态 0===>user_id  授权 添加申请单Id
                StringBuffer sql = new StringBuffer("UPDATE t_objects SET  ").
                        append("   userid_autherized  = '" + dto.getUserId() + "'").append(",").
                        append("   apply  = '" + dto.getId() + "'").
                        append("   WHERE id = '" + dto.getObject_id() + "'");
                jdbcTemplateUtils.update(sql, object);

            }

        }
        return true;
    }


    /* 根据用户Id查询task操作记录（设定的办理人assignee是存的用户id）*/
    public Page<HistoricActivityInstance> searchFinshTask(Integer pageNo, Integer pageSize) {

        String userId = UserUtils.getUserId().toString();//从session中获得当前用户id

        if (!StringUtils.isEmpty(userId)) {

            List<HistoricActivityInstance> list = historyService // 历史任务Service
                    .createHistoricActivityInstanceQuery() // 创建历史活动实例查询
                    .taskAssignee(userId).finished().list();  //

            //对返回的List数据做分页处理
            List list2 = CommonUtils.page(pageSize, pageNo, list);
            //分页相关
            Pageable pageable = new PageRequest(pageNo - 1, pageSize);
            Page<HistoricActivityInstance> page = new PageImpl<>(list2, pageable, list.size());
            return page;
        }
        return null;
    }

    /**
     * 一：使用流程实例ID，查找请假单ID，从而获取请假单信息，查询已完成信息任务详情
     */
    public TChangNameDan detailFinishTask(Integer processInstanceId) {

        //1：使用任务ID，查询任务对象Task
        HistoricProcessInstance hpi = historyService // 历史任务Service
                .createHistoricProcessInstanceQuery() // 创建历史流程实例查询
                .processInstanceId(processInstanceId + "") // 指定流程实例ID
                .singleResult();
        //4：使用流程实例对象获取BUSINESS_KEY
        String buniness_key = hpi.getBusinessKey();
        //5：获取BUSINESS_KEY对应的主键ID，使用主键ID，查询改名单对象（TChangNameDan.1）
        String id = "";
        if (!StringUtils.isEmpty(buniness_key)) {
            //截取字符串，取buniness_key小数点的第2个值
            id = buniness_key.split("\\.")[1];
            TChangNameDan tChangNameDan = tChangNameDanRepository.findOne(Integer.parseInt(id));
            //根据model_id查询车型
            Integer model_id = tChangNameDan.getModel_id();
            if (model_id == 0) {
                tChangNameDan.setObjname(tChangNameDan.getBeforname());
            } else {
                TModels tModels = tModelsRepository.findOne(model_id);
                tChangNameDan.setObjname(tModels.getModelName());
            }

            return tChangNameDan;
        }
        return null;
    }
}






























